#include <cctype>
#include <cstdio>
#include <cstring>
#include <vector>

typedef long long ll;

const int N = 4e5 + 5;
const ll inf = 0x3f3f3f3f3f3f3f3f;

template <typename T>
inline T &read(T &x) {
  x = 0;
  bool f = false;
  short ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = true;
    ch = getchar();
  }
  while (isdigit(ch)) x = x * 10 + (ch ^ '0'), ch = getchar();
  if (f) x = -x;
  return x;
}

template <size_t SIZ>
struct Graph {
  struct Edge {
    int v, nxt, w;
  };

  int e_cnt, heads[SIZ];
  Edge e[SIZ * 2];

  Graph() : e_cnt(1) {}
  inline void add(int u, int v, int w) {
    e[++e_cnt].v = v, e[e_cnt].nxt = heads[u], heads[u] = e_cnt, e[e_cnt].w = w;
    e[++e_cnt].v = u, e[e_cnt].nxt = heads[v], heads[v] = e_cnt, e[e_cnt].w = w;
  }
};

int n, cnt;
int ch[N * 19][2], root[N];
ll ans = -inf;
ll val[N * 19];

namespace Tr1 {

Graph<N> G;
Graph<N * 2> H;

int tot, CG, minn, sum;
int dep[N * 2], siz[N * 2];
bool cut[N * 2];
ll dis[N * 2], disCG[N * 2];

inline void insert(int v, int w, int &ffa) {
  H.add(ffa, ++tot, 0);
  H.add(ffa = tot, v, w);
}

void build(int u, int fa) {
  for (int i = G.heads[u], v, ffa = u; i; i = G.e[i].nxt)
    if ((v = G.e[i].v) != fa) {
      insert(v, G.e[i].w, ffa);
      build(v, u);
    }
}

void dfs(int u, int fa) {
  for (int i = H.heads[u], v; i; i = H.e[i].nxt) {
    if ((v = H.e[i].v) != fa) {
      dis[v] = dis[u] + H.e[i].w;
      dep[v] = dep[u] + 1;
      dfs(v, u);
    }
  }
}

void getRoot(int u, int fa) {
  siz[u] = 1;
  for (int i = H.heads[u], v; i; i = H.e[i].nxt) {
    if ((v = H.e[i].v) != fa && !cut[i >> 1]) {
      getRoot(v, u);
      siz[u] += siz[v];
      int tmp = std::max(siz[v], sum - siz[v]);
      if (minn > tmp) minn = tmp, CG = i;
    }
  }
}

void calc(int u, int fa, const bool typ) {
  if (u <= n) {
    val[++cnt] = dis[u] + disCG[u];
    ch[root[u]][typ] = cnt;
    root[u] = cnt;
  }
  for (int i = H.heads[u], v; i; i = H.e[i].nxt) {
    if ((v = H.e[i].v) != fa && !cut[i >> 1]) {
      disCG[v] = disCG[u] + H.e[i].w;
      calc(v, u, typ);
    }
  }
}

void solve(int u, int last = tot) {
  if (last == 1) return;
  sum = last;
  minn = 0x3f3f3f3f;
  getRoot(u, 0);
  int st = H.e[CG].v, ed = H.e[CG ^ 1].v;
  cut[CG >> 1] = true;
  disCG[st] = H.e[CG].w;
  disCG[ed] = 0;
  calc(st, 0, dep[st] > dep[ed]);
  calc(ed, 0, dep[ed] > dep[st]);
  int tmp = last - siz[st];
  solve(st, siz[st]);
  solve(ed, tmp);
}

}  // namespace Tr1

namespace Tr2 {

Graph<N> G;

ll tmp = -inf, dis[N];

int merge(int a, int b) {
  if (!(a && b)) return a | b;
  if (ch[a][0] && ch[b][1]) { tmp = std::max(tmp, val[ch[a][0]] + val[ch[b][1]]); }
  if (ch[a][1] && ch[b][0]) { tmp = std::max(tmp, val[ch[a][1]] + val[ch[b][0]]); }
  ch[a][0] = merge(ch[a][0], ch[b][0]);
  ch[a][1] = merge(ch[a][1], ch[b][1]);
  val[a] = std::max(val[a], val[b]);
  return a;
}

void dfs(int u, int fa) {
  for (int i = G.heads[u], v; i; i = G.e[i].nxt) {
    if ((v = G.e[i].v) != fa) {
      dis[v] = dis[u] + G.e[i].w;
      dfs(v, u);
      tmp = -inf;
      root[u] = merge(root[u], root[v]);
      if (tmp != -inf) ans = std::max(ans, tmp - dis[u] * 2);
    }
  }
}

}  // namespace Tr2

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
  freopen64("/tmp/CodeTmp/testdata.in", "r", stdin);
  freopen64("/tmp/CodeTmp/testdata.out", "w", stdout);
#else
  freopen("P4565 [CTSC2018]暴力写挂.in", "r", stdin);
  freopen("P4565 [CTSC2018]暴力写挂.out", "w", stdout);
#endif
#endif

  cnt = Tr1::tot = read(n);
  val[0] = -inf;
  for (int i = 1, u, v, w; i < n; ++i) {
    read(u), read(v), read(w);
    Tr1::G.add(u, v, w);
  }
  for (int i = 1, u, v, w; i < n; ++i) {
    read(u), read(v), read(w);
    Tr2::G.add(u, v, w);
  }
  Tr1::build(1, 0), Tr1::dfs(1, 0);
  for (int i = 1; i <= n; ++i) root[i] = i;
  Tr1::solve(1);
  for (int i = 1; i <= n; ++i) root[i] = i;
  Tr2::dfs(1, 0);
  ans /= 2;
  for (int i = 1; i <= n; ++i) { ans = std::max(ans, Tr1::dis[i] - Tr2::dis[i]); }
  printf("%lld", ans);
  return 0;
}